import { Injectable } from '@nestjs/common';
import { Role_CreateDto, Role_UpdateDto } from './assets/role.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Role } from './assets/role.entity';
import {
  util_Db_Add,
  util_Db_Delete,
  util_Db_NoPageList,
  util_Db_PageList,
  util_Db_Update,
} from '@/common/util/db';
import { Role_FindDto } from './assets/role.dto';
import { Menu } from '../menu/assets/menu.entity';
import { UserAdmin_Service } from '../userAdmin/userAdmin.service';
import { Class_HttpException_Base } from '@/common/classes/httpException';

@Injectable()
export class Role_Service {
  constructor(
    @InjectRepository(Role)
    private role_Repository: Repository<Role>,
    @InjectRepository(Menu)
    private menu_Repository: Repository<Menu>,
    private userAdmin_Service: UserAdmin_Service,
  ) {}

  async role_Create(body: Role_CreateDto) {
    const menus = [];
    body.menu.map((item) => {
      menus.push(this.menu_Repository.create({ id: item }));
    });
    body.menu = menus;
    return await util_Db_Add({
      createDto: body,
      repository: this.role_Repository,
    });
  }

  async role_FindAllSelect() {
    return await util_Db_NoPageList({
      queryBuilder: this.role_Repository
        .createQueryBuilder('role')
        .select(['role.id AS id', 'role.roleName AS name'])
        .orderBy('role.id', 'DESC'),
      isRaw: true,
    });
  }

  async role_FindByPage(query: Role_FindDto) {
    const { size, page, roleName } = query;
    const { list, totalElements } = await util_Db_PageList<Role>({
      queryBuilder: this.role_Repository
        .createQueryBuilder('role')
        .leftJoinAndSelect('role.menu', 'menu')
        .leftJoinAndSelect('menu.parent', 'parent'),
      query: { 'role.roleName': roleName, page, size },
    });
    list.map((data) => {
      const allMenuIds = new Set(data.menu.map((menuItem) => menuItem.id));
      data.menu.forEach((menuItem) => {
        if (menuItem.parent) {
          allMenuIds.delete(menuItem.parent.id);
        }
      });
      data.menu = Array.from(allMenuIds) as unknown as Menu[];
    });
    return {
      totalElements,
      list,
    };
  }

  async role_FindMenu(id: number) {
    return await this.role_Repository
      .createQueryBuilder('role')
      .leftJoinAndSelect('role.menu', 'menu')
      .leftJoinAndSelect('menu.parent', 'parent')
      .andWhere(`role.id = :id`, { id: id })
      .andWhere(`menu.isMenu = :isMenu`, { isMenu: true })
      .andWhere(`menu.canUse = :canUse`, { canUse: true })
      .andWhere(`menu.isExpandMenu IN (:...isExpandMenu)`, {
        isExpandMenu: ['show', 'expand'],
      })
      .orderBy('menu.menuOrder', 'ASC')
      .getOne();
  }

  async role_Menu_Route(id: number) {
    return await this.role_Repository
      .createQueryBuilder('role')
      .leftJoinAndSelect('role.menu', 'menu')
      .leftJoinAndSelect('menu.parent', 'parent')
      .andWhere(`role.id = :id`, { id: id })
      .andWhere(`menu.isMenu = :isMenu`, { isMenu: true })
      .andWhere(`menu.canUse = :canUse`, { canUse: true })
      .andWhere(`menu.isExpandMenu IN (:...isExpandMenu)`, {
        isExpandMenu: ['show', 'hide'],
      })
      .getOne();
  }

  async role_Update(body: Role_UpdateDto) {
    const menus = [];
    body.menu.map((item) => {
      menus.push(this.menu_Repository.create({ id: item }));
    });
    body.menu = menus;
    return await util_Db_Update({
      findOne: () => this.role_FindOneById(body.id),
      updateDto: body,
      repository: this.role_Repository,
    });
  }

  async role_Remove(id: number) {
    const userAdmin = await this.userAdmin_Service.userAdmin_FindOneByQuery({ roleId: id });
    if (userAdmin) throw new Class_HttpException_Base('存在该角色的用户');
    return await util_Db_Delete({
      findOne: () => this.role_FindOneById(id),
      id,
      repository: this.role_Repository,
    });
  }

  async role_FindOneById(id: number) {
    return await this.role_Repository
      .createQueryBuilder('role')
      .leftJoinAndSelect('role.menu', 'menu')
      .leftJoinAndSelect('menu.parent', 'parent')
      .andWhere(`role.id = :id`, { id: id })
      .getOne();
  }
}
